/**************************************************************************
 **       Title: Turn a Digital Camera into a V4L device using vloopback
 **    $RCSfile: dc_captura.c,v $
 **   $Revision: 1.2 $$Name:  $
 **       $Date: 2008-01-24 14:45:13 $
 **   Copyright: LGPL $Author: ricardo $
 ** Description:
 **
 **    Sends format0 640x480 RGB to the vloopback input device so that it
 **    can be consumed by V4L applications on the vloopback output device.
 **    Get vloopback 0.90 from http://motion.technolust.cx/vloopback/
 **    Apply the patch from effectv http://effectv.sf.net/
 **    It has been tested with EffecTV (exciting!), GnomeMeeting, ffmpeg,
 **    camsource, Kino, and veejay.
 **
 ** TODO:
 **    - Support video controls
 **    - do cropping on v4l window offset
 **    - supply audio from sound card?
 **
 **-------------------------------------------------------------------------
 **
 **  $Log: dc_captura.c,v $
 **  Revision 1.2  2008-01-24 14:45:13  ricardo
 **  SoluciÃ³n problema de retorno de carro y modificaciÃ³n del fichero
 **  dc1394_multiview.c del modo 7 height = 1040 width=1392
 **
 **  Revision 1.1.1.1  2008-01-22 12:03:01  ricardo
 **  cabintec_captura
 **
 **  Revision 1.5  2007/05/10 11:10:20  pjf
 **  Funcionando 2 cams en el mismo bus o distinto a 800
 **
 **  Revision 1.4  2007/05/10 10:30:31  pjf
 **  no funciona camaras mismo bus
 **  funciona distintos buses
 **
 **  Revision 1.3  2007/05/09 10:19:57  pjf
 **  sin crlf con dos2unix
 **
 **  Revision 1.2  2007/05/09 10:16:48  pjf
 **  cambiado orden sÂ¡disparo al correcto
 **
 **  Revision 1.12  2005/12/21 11:22:49  ddouxchamps
 **  Fixed compilation warning and a bug in camera detection
 **
 **  Revision 1.11  2004/08/10 07:57:22  ddouxchamps
 **  Removed extra buffering (Johann Schoonees)
 **
 **  Revision 1.10  2004/03/09 08:41:44  ddouxchamps
 **  patch from Johann Schoonees for extra buffering
 **
 **  Revision 1.9  2004/01/20 04:15:34  ddennedy
 **  workaround some potential V4L compilation error
 **
 **  Revision 1.8  2004/01/20 04:12:27  ddennedy
 **  added dc1394_free_camera_nodes and applied to examples
 **
 **  Revision 1.7  2004/01/14 22:20:43  ddennedy
 **  enhanced dc1394_vloopback
 **
 **  Revision 1.6  2004/01/04 21:27:56  ddennedy
 **  simplify video1394 includes and other minor corrections
 **
 **  Revision 1.5  2003/09/23 13:44:12  ddennedy
 **  fix camera location by guid for all ports, add camera guid option to vloopback, add root detection and reset to vloopback
 **
 **  Revision 1.4  2003/09/15 17:21:27  ddennedy
 **  add features to examples
 **
 **  Revision 1.1  2002/10/27 04:21:54  ddennedy
 **  added v4l utility using vloopback
 **
 **
 **************************************************************************/

#include "dc_captura.h"


/***** IMAGE PROCESSING *******************************************************/

typedef void (*affine_transform_cb)(const unsigned char *src, unsigned char *dest);

void transform_yuv422(const unsigned char *src, unsigned char *dest)
{
    swab(src, dest, 4);
}

void transform_rgb24(const unsigned char *src, unsigned char *dest)
{
    dest[2] = src[0]; //b
    dest[1] = src[1]; //g
    dest[0] = src[2]; //r
}
/*
void affine_scale( const unsigned char *src, int src_width, int src_height, unsigned char *dest, int dest_width, int dest_height,
                   int bpp, affine_transform_cb transform )
{	
    affine_transform_t affine;
    double scale_x = (double) dest_width / (double) src_width;
    double scale_y = (double) dest_height / (double) src_height;
    register unsigned char *d = dest;
    register const unsigned char  *s = src;
    register int i, j, x, y;

    // optimization for no scaling required 
    if (scale_x == 1.0 && scale_y == 1.0) {
	for (i = 0; i < src_width*src_height; i++) {
	    transform(s, d);
	    s += bpp;
	    d += bpp;
	}
	return;
    }
	
    affine_transform_init( &affine );
	
    if ( scale_x <= 1.0 && scale_y <= 1.0 )
    {
	affine_transform_scale( &affine, scale_x, scale_y );

	for( j = 0; j < src_height; j++ )
	    for( i = 0; i < src_width; i++ )
	    {
		x = (int) ( affine_transform_mapx( &affine, i - src_width/2, j - src_height/2 ) );
		y = (int) ( affine_transform_mapy( &affine, i - src_width/2, j - src_height/2 ) );
		x += dest_width/2;
		x = CLAMP( x, 0, dest_width);
		y += dest_height/2;
		y = CLAMP( y, 0, dest_height);
		s = src + (j*src_width*bpp) + i*bpp;
		d = dest + y*dest_width*bpp + x*bpp;
		transform(s, d);
		d += bpp;
		s += bpp;
	    }
    }
    else if ( scale_x >= 1.0 && scale_y >= 1.0 )
    {
	affine_transform_scale( &affine, 1.0/scale_x, 1.0/scale_y );
	
	for( y = 0; y < dest_height; y++ )
	    for( x = 0; x < dest_width; x++ )
	    {
		i = (int) ( affine_transform_mapx( &affine, x - dest_width/2, y - dest_height/2 ) );
		j = (int) ( affine_transform_mapy( &affine, x - dest_width/2, y - dest_height/2 ) );
		i += src_width/2;
		i = CLAMP( i, 0, dest_width);
		j += src_height/2;
		j = CLAMP( j, 0, dest_height);
		s = src + (j*src_width*bpp) + i*bpp;
		d = dest + y*dest_width*bpp + x*bpp;
		transform(s, d);
		d += bpp;
		s += bpp;
	    }
    }
}
*/
inline void
yuy2_to_yv16( const unsigned char *src, unsigned char *dest, int width, int height)
{
    register int total = (width * height) >> 1;
    register int i;
    register unsigned char *img_y = dest;
    register unsigned char *img_cb = img_y + (width * height);
    register unsigned char *img_cr = img_cb + total;

    for (i = 0; i < total; i++) {
	*img_y++  = *src++;
	*img_cb++ = *src++;
	*img_y++  = *src++;
	*img_cr++ = *src++;
    }
}

inline void
yuy2_to_yv12( const unsigned char *src, unsigned char *dest, int width, int height)
{
    register int stride = width >> 1;
    register int i, j;
    register unsigned char *img_y = dest;
    register unsigned char *img_cb = img_y + (width * height);
    register unsigned char *img_cr = img_cb + stride * (height >> 1);

    for (i = 0; i < height; i++) {
	for (j = 0; j < stride; j++) {
	    if (i%2) {
		*img_y++  = *src++;
		src++;
		*img_y++  = *src++;
		src++;
	    } else {
		*img_y++  = *src++;
		*img_cb++ = (src[width << 1] + src[0]) >> 1;
		src++;
		*img_y++  = *src++;
		*img_cr++ = (src[width << 1] + src[0]) >> 1;
		src++;
	    }
	}
    }
}


inline void yuv422_to_gray( const unsigned char *src, unsigned char *dest, int width, int height)
{
    register int i, numPixels;
    register unsigned char *src_, *dest_;


    src_ = (unsigned char *)src;
    dest_ = (unsigned char *)dest;
    src_++;

    numPixels = height*width;


    for (i = 0; i < numPixels; i++) {
	*(dest_++)=*(src_+=2); 

    }
}


/***** DIGITAL CAMERA *********************************************************/

int dc_init(camera_control *cameras)
{
    struct raw1394_portinfo ports[MAX_PORTS];
    int numPorts = MAX_PORTS;
    int port, reset,a;
    int camCount = 0,cam=0;
    int found = 0,channel=0;
    raw1394handle_t p_handles[8];
    raw1394handle_t handle = NULL;
    /* declarations for libdc1394 */
    nodeid_t *camera_nodes;
    int numCams;

    /* get the number of ports (cards) */
    handle = raw1394_new_handle();
 
    if (handle==NULL) 
    {
	perror("Unable to aquire a raw1394 handle\n");
	perror("did you load the drivers?\n");
	return 0;
    }
  
    numPorts = raw1394_get_port_info(handle, ports, numPorts);

    printf("\nNumber  of cards %d\n", numPorts);

    raw1394_destroy_handle(handle);
    handle = NULL;
    numCams=0;

    for (reset = 0; reset < MAX_RESETS && found!=1; reset++) 
    {
	/* get dc1394 handle to each port (card)*/

	for (port = 0; port < numPorts  ; port++) /* Program video1394 */
	{
	    channel=0;
	    printf("\nNueva tarjeta\n");

	    if (handle != NULL)               /* Recogemos el handle para la tarjeta */
		dc1394_destroy_handle(handle);
	    p_handles[port]/*handle*/ = dc1394_create_handle(port);
	    if (p_handles[port]/*handle*/==NULL) 
	    {
		perror("Unable to aquire a raw1394 handle\n");
		perror("did you load the drivers?\n");
		return 0;
	    }

      
	    /* get the camera nodes and describe them as we find them */
	    /* Tomamos lo que haya conectado a los distintos conectores y ponemos
	       su informaciï¿½n */

	    camCount = 0;

	    camera_nodes = dc1394_get_camera_nodes(p_handles[port]/*handle*/, &camCount, 0);

	    /*Si encontramos algo conectado a la tarjeta */
	    printf("\nCard %d, %d cameras found\n",port, camCount);

	    if (camCount > 0) 
	    {
		/* Podemos buscar los dispositivos por guid pasï¿½ndoselo como
		   parï¿½metro */

		/* Monocromo scA 1400-17fm --> GUID 0x003053-00013bf6ac
		   Color     scA 1400-17fc --> GUID 0x003053-00013a97a3*/

		if (cameras[numCams].g_guid == 0) 
		{
		    for (cam = 0; cam < camCount ; cam++) 
		    {
			cameras[numCams].handle=p_handles[port];
			dc1394_camerainfo info;
			if (dc1394_get_camera_info(cameras[numCams].handle, camera_nodes[cam], &info) == DC1394_SUCCESS)	
			{
			    dc1394_print_camera_info(&info);
			    cameras[numCams].g_guid = info.euid_64;
			    cameras[numCams].UID[0]= info.euid_64 & 0xffffffff;
			    cameras[numCams].UID[1]= (info.euid_64 >>32) & 0xffffffff;
			    strcpy(cameras[numCams].vendor, info.vendor);
			    strcpy(cameras[numCams].model, info.model);
			    cameras[numCams].camera.node = camera_nodes[cam];
			    cameras[numCams].channel = channel;
			    found = 1;
			    numCams++;
			    channel++;
			}
		    }
		}
		else 
		{
		    /* attempt to locate camera by guid */
		    int cam;
		    for (cam = 0; cam < camCount && found == 0; cam++) 
		    {
			cameras[numCams].handle=p_handles[port];
			dc1394_camerainfo info;
			if (dc1394_get_camera_info(cameras[numCams].handle, camera_nodes[cam], &info) == DC1394_SUCCESS)	
			{
			    if (info.euid_64 == cameras[numCams].g_guid)	
			    {
				dc1394_print_camera_info(&info);
				cameras[numCams].UID[0]= info.euid_64 & 0xffffffff;
				cameras[numCams].UID[1]= (info.euid_64 >>32) & 0xffffffff;
				strcpy(cameras[numCams].vendor, info.vendor);
				strcpy(cameras[numCams].model, info.model);
				cameras[numCams].camera.node = camera_nodes[cam];
				cameras[numCams].channel = channel;
				found = 1;
				numCams++;
				channel++;
			    }
			}
		    }
		}


		if (found == 1)	
		{
		    /* camera can not be root--highest order node */
		    if (cameras[numCams-1].camera.node == raw1394_get_nodecount(p_handles[port]/*handle*/)-1)
		    {
			/* reset and retry if root */
			printf("\nReset!!!!\n");
			raw1394_reset_bus(p_handles[port]/*handle*/);
			sleep(2);
			found = 0;
		    }
		}
		dc1394_free_camera_nodes(camera_nodes);
	    } /* camCount > 0 */
	} /* next port */
    } /* next reset retry */


    if (found == 0 && cameras[0].g_guid != 0) 
    {
	fprintf( stderr, "Unable to locate camera node by guid\n");
	return 0;
    }
    else if (camCount == 0 && found==0) 
    {
	fprintf( stderr, "no cameras found :(\n");
	return 0;
    }
  
    if (reset == MAX_RESETS) 
    {
	fprintf( stderr, "failed to not make camera root node :(\n");
	return 0;
    }
    else 
	for (a=0;a<numCams;a++)
	    cameras[a].numCams=numCams;

    return found;
}

int dc_config(camera_control *cameras, int width, int height, int xoffset, int yoffset)
{
    int a=0;
 
    for(a=0;a<cameras[0].numCams;a++)
    {
	if (width > 0 && height > 0)
	{
	    cameras[a].width = width;
	    cameras[a].height = height;
	    cameras[a].offset_width = xoffset;
	    cameras[a].offset_height = yoffset;
	}
	if (cameras[a].speed==SPEED_800)
	    dc1394_set_operation_mode
		(cameras[a].handle, 
		 cameras[a].camera.node, 
		 OPERATION_MODE_1394B);
    
	if (dc1394_set_iso_channel_and_speed
	    (cameras[a].handle,
	     cameras[a].camera.node,
	     cameras[a].channel, 
	     cameras[a].speed) !=DC1394_SUCCESS) 
	{
	    printf("unable to get the iso channel number\n");
	    return 0;
	}
    
	switch(cameras[a].speed)
	{
	case SPEED_100:
	    printf("\nBUS SPEED 100Mbps\n");
	    break;
	case SPEED_200:
	    printf("\nBUS SPEED 200Mbps\n");
	    break;
	case SPEED_400:
	    printf("\nBUS SPEED 400Mbps\n");
	    break;
	case SPEED_800:
	    printf("\nBUS SPEED 800Mbps\n");
	    break;
	case SPEED_1600:
	    printf("\nBUS SPEED 1600Mbps\n");
	    break;
	case SPEED_3200:
	    printf("\nBUS SPEED 3200Mbps\n");
	    break;
	default:
	    printf("\nBUS SPEED ERROR!!\n");
	    break;
	}

	if(cameras[a].ext_trigger)
	{
	    dc1394_set_trigger_polarity(cameras[a].handle,cameras[a].camera.node ,(dc1394bool_t)1);
	    dc1394_set_trigger_mode(cameras[a].handle, cameras[a].camera.node, 0);
	    dc1394_unset_soft_trigger(cameras[a].handle, cameras[a].camera.node);
	    dc1394_set_trigger_on_off(cameras[a].handle, cameras[a].camera.node, (dc1394bool_t)1);
	}
	else
	    dc1394_set_trigger_on_off(cameras[a].handle, cameras[a].camera.node, (dc1394bool_t)0);
    
    
	/*   FORMAT_SVGA_NONCOMPRESSED_2,
	     MODE_1600x1200_RGB, MODE_1600x1200_YUV422, MODE_1280x960_RGB, MODE_1280x960_YUV422,
	     MODE_1600x1200_MONO, MODE_1280x960_MONO, MODE_1600x1200_MONO16, MODE_1280x960_MONO16,
	     FORMAT_SVGA_NONCOMPRESSED_1,
	     MODE_1024x768_RGB, MODE_1024x768_YUV422, MODE_800x600_RGB, MODE_800x600_YUV422,
	     MODE_1024x768_MONO, MODE_800x600_MONO, MODE_1024x768_MONO16, MODE_800x600_MONO16, 
	     FORMAT_VGA_NONCOMPRESSED,
	     MODE_640x480_RGB, MODE_640x480_YUV422, MODE_640x480_YUV411, MODE_320x240_YUV422,
	     MODE_160x120_YUV444, MODE_640x480_MONO, MODE_640x480_MONO16,
	     FORMAT_SCALABLE_IMAGE_SIZE,
	     MODE_FORMAT7_0, MODE_FORMAT7_1, MODE_FORMAT7_2, MODE_FORMAT7_3,
	     MODE_FORMAT7_4, MODE_FORMAT7_5, MODE_FORMAT7_6, MODE_FORMAT7_7,*/
    
    
	if (cameras[a].mode < MODE_FORMAT7_0)
	{
	    printf("\nNO MODO 7 camera handle = %p camera node %d channel %d format %d mode %d speed %d fr %d ndmab %d df %d dev_name %s camera %p\n",
		   cameras[a].handle, cameras[a].camera.node, cameras[a].channel, cameras[a].format, cameras[a].mode,
		   cameras[a].speed, cameras[a].frame_rate, cameras[a].num_dma_buffers,
		   cameras[a].drop_frames, cameras[a].dc_dev_name, (void*)&cameras[a].camera);
      
	    if (dc1394_dma_setup_capture(cameras[a].handle,cameras[a].camera.node, cameras[a].channel,
					 cameras[a].format, cameras[a].mode,
					 cameras[a].speed, cameras[a].frame_rate, cameras[a].num_dma_buffers,
					 cameras[a].drop_frames, cameras[a].dc_dev_name, &cameras[a].camera) != DC1394_SUCCESS) 
	    {
		fprintf(stderr, "unable to setup camera- check line %d of %s to make sure\n",
			__LINE__,__FILE__);
		perror("that the video mode,framerate and format are supported\n");
		fprintf(stderr, "is one supported by your camera\n");
		return 0;
	    }
	}
	else
	{
	    printf("\nMODO 7 camera handle = %p camera node %d channel %d\n",
		   cameras[a].handle, cameras[a].camera.node, cameras[a].channel);
      
	    dc1394_set_format7_color_coding_id
		(cameras[a].handle, 
		 cameras[a].camera.node, 
		 cameras[a].mode,
		 cameras[a].color_format);

	    printf("\nSize %d %d\n",cameras[a].width, cameras[a].height);

	    dc1394_dma_setup_format7_capture
		(cameras[a].handle, 
		 cameras[a].camera.node,
		 cameras[a].channel,
		 cameras[a].mode, 
		 cameras[a].speed, 
		 cameras[a].packet_size, 
		 cameras[a].offset_width,
		 cameras[a].offset_height,
		 cameras[a].width, 
		 cameras[a].height,
		 cameras[a].num_dma_buffers, 
		 cameras[a].drop_frames,
		 cameras[a].dc_dev_name, 
		 &cameras[a].camera);
	}
	cameras[a].frame_size = cameras[a].camera.quadlets_per_frame * 4;
    }

    return 1;
}


int dc_start_iso(camera_control *cameras)
{
    int a,j;

    for(a=0;a<cameras[a].numCams;a++)
    {   
	dc_get_features(cameras,a);        /* Obtenemos las caracteristicas de la
					      camara */
	//dc_print_features(cameras,a);      /* Las mostramos por pantalla */
	dc_set_features(cameras,a);        /* Ponemos en automático todas las que
					      se puedan poner */

	for(j=0; j<FEATURE_MAX-FEATURE_MIN;j++)        /* Las que hemos recibido
							  por la línea de comandos las ponemos al valor introducido */
	    if(cameras[a].feature_set.feature[j].target_value)
	    {
		if(cameras[a].feature_set.feature[j].target_value==-1)
		    cameras[a].feature_set.feature[j].target_value=0;

		dc_set_feature
		    (cameras, a, 
		     cameras[a].feature_set.feature[j].feature_id, 
		     cameras[a].feature_set.feature[j].target_value);
	    }

	if (dc1394_start_iso_transmission(cameras[a].handle, cameras[a].camera.node) !=DC1394_SUCCESS)
	{
	    perror("unable to start camera iso transmission\n");
	    return 0;
	}
    }

    //dc1394_start_iso_transmission(cameras[0].handle, 63);

    printf("\nStarted ISO transmision\n");

    return 1;
}

	

/***** MAIN *******************************************************************/


void default_options(camera_control *cameras)
{
    int a=3,i=0,j;

    for (i=0;i<MAX_CAMERAS;i++)
    {
	/*********    Camera Members   **********/
	cameras[i].handle=0;
	cameras[i].image=0;
	cameras[i].numCams=0;      
	cameras[i].g_guid=0; 
	cameras[i].UID[0]=0;
	cameras[i].UID[1]=0;
	cameras[i].written_frame=0;
	cameras[i].frame_size=0;

	/*********    Configuration Members   **********/
	cameras[i].num_dma_buffers=0;
	cameras[i].channel=0;
	cameras[i].speed=0;

	for(j=0; j<FEATURE_MAX-FEATURE_MIN;j++)
	    cameras[i].feature_set.feature[j].target_value=0;

	cameras[i].dc_dev_name=0;
   
	if(a==3)
	{ 
	    cameras[i].drop_frames = 0;    /* NO DROP FRAMES */
	    cameras[i].num_dma_buffers = 30; 
	    cameras[i].width = MAX_RESOLUTION_WIDTH;
	    cameras[i].height = MAX_RESOLUTION_HEIGHT;
	    cameras[i].offset_width = OFFSET_WIDTH;
	    cameras[i].offset_height = OFFSET_HEIGHT;
	    cameras[i].mode =  MODE_FORMAT7_0;
	    cameras[i].format =  FORMAT_SCALABLE_IMAGE_SIZE;
	    cameras[i].color_format = COLOR_FORMAT7_MONO8;
	    cameras[i].speed = SPEED_800;
	    cameras[i].frame_rate = FRAMERATE_30;
	    cameras[i].packet_size = 4096;
	    cameras[i].soft_resync = 0 ;
	    cameras[i].ext_trigger = 0;
	    cameras[i].color = BN;
	}
    }
}

inline double difftime_ms(struct timeval t2, struct timeval t1)
{
    return (double)(t2.tv_sec - t1.tv_sec)*1.0e3 + (double)(t2.tv_usec - t1.tv_usec)/1.0e3;
}


void dc_cameras_resync(camera_control *cameras, int max_diff, int blocking)
{
    int diff = 100;
    int stop_iso=0;
    char c;

    /*-------------------------------------------*/
    while(abs(diff)>max_diff)
    {

	dc1394_dma_single_capture(&cameras[0].camera);
	dc1394_dma_single_capture(&cameras[1].camera);
	dc1394_dma_done_with_buffer(&cameras[0].camera);
	dc1394_dma_done_with_buffer(&cameras[1].camera);
 
	diff = (int)difftime_ms (cameras[0].camera.filltime, cameras[1].camera.filltime);

	if(abs(diff)>max_diff)
	{
	    printf("\nResincronizando %d ms\n",diff);
	    if(diff>0)
	    {
		dc1394_dma_single_capture(&cameras[1].camera);
		dc1394_dma_done_with_buffer(&cameras[1].camera);
	    }
	    else
	    {
		dc1394_dma_single_capture(&cameras[0].camera);
		dc1394_dma_done_with_buffer(&cameras[0].camera);
	    }

	    stop_iso++;
	    if(stop_iso==MAX_SYNC_TRY)
	    {
		if (blocking)
		{
		    printf("\nReiniciando\n");
		    stop_iso=0;
		    dc1394_stop_iso_transmission(cameras[0].handle, cameras[0].camera.node);
		    dc1394_stop_iso_transmission(cameras[1].handle, cameras[1].camera.node);
		    dc1394_dma_unlisten(cameras[0].handle, &cameras[0].camera);
		    dc1394_dma_unlisten(cameras[1].handle, &cameras[1].camera);
		    dc1394_dma_release_camera(cameras[0].handle, &cameras[0].camera);
		    dc1394_dma_release_camera(cameras[1].handle, &cameras[1].camera);
		    dc1394_camera_off(cameras[0].handle, cameras[0].camera.node);
		    dc1394_camera_off(cameras[1].handle, cameras[1].camera.node);

		    printf("\nATENCIÓN: Está capturando con %d cámaras y su desincronización es de %d ms\n", cameras[0].numCams,diff);
		    printf("\nSi desea resincronizar desenchufe las cámaras, vuelva a enchufarlas y presione r, si no pulse cualquier otra tecla...\n");

		    c = getchar();
		    getchar();  

		    if (dc_init(cameras) < 1) {
			fprintf(stderr, "no cameras found :(\n");
			return;
		    }

		    if ( !dc_config(cameras, 0, 0, 0, 0) ) {
			fprintf(stderr, "Failed to start dc1394 capture");
			return;
		    }

		    dc_start_iso(cameras);
	  
		    if(c!='r')
			diff=0;
		}
		else
		    diff=0;
	    }
	}
	else if (diff==0)
	    printf("Desincronizacion %d ms. No se continúa con la resincronizacion\n\n",diff);
	else
	    printf("Desincronizacion %d ms. No necesaria resincronizacion\n\n",diff);
      
    }

    /**************************************************************************************/

    /*-----------------------------------------------*/

  
}


int dc_capture(camera_control *cameras, int camNum)
{
    int a;
    
    if (camNum==0)
    {
	for (a=0;a<cameras[0].numCams;a++)
	{
	    if (dc1394_dma_single_capture(&cameras[a].camera) != DC1394_SUCCESS) 
	    {
		printf("\nERROR while adquiring...\n");
		return -1;
	    }
	}
	for (a=0;a<cameras[0].numCams;a++)
	{
	    //cameras[a].image->imageData = ( char*) cameras[a].camera.capture_buffer;
	    cameras[a].image_tmp->imageData = ( char*) cameras[a].camera.capture_buffer;
	    cvCopy(cameras[a].image_tmp, cameras[a].image);
	    //cameras[a].image = cvCloneImage(cameras[a].image_tmp);
	    dc1394_dma_done_with_buffer(&cameras[a].camera);
	}
    }
    else
    {
	if (dc1394_dma_single_capture(&cameras->camera) != DC1394_SUCCESS) 
	{
	    printf("\nERROR while adquiring...\n");
	    return -1;
	}
	//cameras->image->imageData = ( char*) cameras->camera.capture_buffer;
	cameras->image_tmp->imageData = ( char*) cameras->camera.capture_buffer;
	cvCopy(cameras->image_tmp, cameras->image);
	//cameras->image = cvCloneImage(cameras->image_tmp);
	dc1394_dma_done_with_buffer(&cameras->camera);
    }

    return 1;  
}

/* Abre y crea la cabecera de los ficheros mtr que contienen la fecha y versión del
   programa que los guardó la longitud del video (se rellena al final), el
   número de cámaras y la estructura camera_control (todo en ASCII) */


//************************************************************************
//  FUNCIÓN QUE RESERVA MEMORIA Y CREA UNA VENTANA PARA UNA IMAGEN OPENCV 
//
//       cameras -> Puntero a la estructura camera_control que contiene las
//       cámaras que se quieren mostrar
//
//       camNum -> Número de cámara que se quiere mostrar. Si
//       es 0 se reservam las imágenes de todas las cámaras que haya en la
//       estructura cameras.
//   
//************************************************************************
int dc_init_images(camera_control *cameras, int camNum)
{
    int a;
  
    if (camNum)
    {
	cameras[camNum-1].image_tmp = 
	    cvCreateImage
	    (cvSize(cameras[camNum-1].width,cameras[camNum-1].height),
	     IPL_DEPTH_8U,cameras[camNum-1].color);
	cameras[camNum-1].image = cvCloneImage(cameras[camNum-1].image_tmp);
    }
    else
    {
	for(a=0;a<cameras[0].numCams;a++)
	{
	    cameras[a].image_tmp = 
		cvCreateImage
		(cvSize(cameras[a].width,cameras[a].height), 
		 IPL_DEPTH_8U,cameras[a].color);
	    cameras[a].image = cvCloneImage(cameras[a].image_tmp);
	}
    }
    return 1;
}

int dc_get_features(camera_control *cameras, int camNum)
{
    return dc1394_get_camera_feature_set(cameras[camNum].handle, cameras[camNum].camera.node, &cameras[camNum].feature_set);
}

void dc_print_features(camera_control *cameras, int camNum)
{
    return dc1394_print_feature_set(&cameras[camNum].feature_set);
}

void dc_print_single_feature(dc1394_feature_info *feature)
{
    return dc1394_print_feature(feature);
}

int dc_check_feature_limits(dc1394_feature_info *feature, int value)
{
    if(value > feature->max || value < feature->min)
	return 0;
    else
	return 1;
}

int dc_trigger_external_mode_on (camera_control *cameras, int camNum)
{
    int a;

    if (camNum)
    {
	// Set the trigger polatity when the camera is using a hardware trigger.
	// High active input
	dc1394_set_trigger_polarity
	    (cameras->handle,
	     cameras->camera.node,
	     (dc1394bool_t)HIGH_ACTIVE_INPUT);
 
	dc1394_set_trigger_mode
	    (cameras->handle, 
	     cameras->camera.node, 
	     TRIGGER_MODE_PROGRAMMABLE);
	//       TRIGGER_MODE_LEVEL);
 
	dc1394_unset_soft_trigger
	    (cameras->handle, 
	     cameras->camera.node);
 
	dc1394_set_trigger_on_off
	    (cameras->handle, 
	     cameras->camera.node,  
	     (dc1394bool_t)ON_TRIGGER_MODE);
    }
    else
    {
	for (a=0; a < cameras[0].numCams; a++)
	{
	    // Set the trigger polatity when the camera is using a hardware trigger.
	    // High active input
	    dc1394_set_trigger_polarity
		(cameras[a].handle,
		 cameras[a].camera.node,
		 (dc1394bool_t)HIGH_ACTIVE_INPUT);
     
	    dc1394_set_trigger_mode
		(cameras[a].handle, 
		 cameras[a].camera.node, 
		 TRIGGER_MODE_PROGRAMMABLE);
	    //         TRIGGER_MODE_LEVEL);
     
	    dc1394_unset_soft_trigger
		(cameras[a].handle, 
		 cameras[a].camera.node);
     
	    dc1394_set_trigger_on_off
		(cameras[a].handle, 
		 cameras[a].camera.node,  
		 (dc1394bool_t)ON_TRIGGER_MODE);
	}
    }

    return 1;
}

int dc_trigger_external_mode_off (camera_control *cameras, int camNum)
{
    int a;

    if (camNum)
    {
	// Set the trigger polatity when the camera is using a hardware trigger.
	// High active input
	dc1394_set_trigger_on_off
	    (cameras->handle, 
	     cameras->camera.node,  
	     (dc1394bool_t)OFF_TRIGGER_MODE);
    }
    else
    {
	for (a=0; a < cameras[0].numCams; a++)
	{
	    // Set the trigger polatity when the camera is using a hardware trigger.
	    // High active input
	    dc1394_set_trigger_on_off
		(cameras[a].handle, 
		 cameras[a].camera.node,  
		 (dc1394bool_t)OFF_TRIGGER_MODE);
	}
    }

    return 1;
}

int dc_set_feature(camera_control *cameras, int camNum, int feature, int value)
{
    if(!cameras[camNum].feature_set.feature[feature-FEATURE_MIN].available)
    {
	printf("\nERROR Feature not available\n");
	return -1;
    }
    
    if(cameras[camNum].feature_set.feature[feature-FEATURE_MIN].auto_active)
	dc_auto_on_off_feature(cameras, camNum, feature, false);
  
    if(!dc_check_feature_limits(&cameras[camNum].feature_set.feature[feature-FEATURE_MIN], value))
    {
	printf("\nERROR Could not set feature, out of limits\n");
	if(value<cameras[camNum].feature_set.feature[feature-FEATURE_MIN].min)
	    cameras[camNum].feature_set.feature[feature-FEATURE_MIN].value=
		cameras[camNum].feature_set.feature[feature-FEATURE_MIN].min;
	else
	    cameras[camNum].feature_set.feature[feature-FEATURE_MIN].value=
		cameras[camNum].feature_set.feature[feature-FEATURE_MIN].max;
	return -1;
    }


    switch(feature) {
    case FEATURE_TEMPERATURE:
	if (dc1394_set_temperature(cameras[camNum].handle, cameras[camNum].camera.node,value)!=DC1394_SUCCESS)
	    printf("\nCould not set temperature\n");
	else
	    cameras[camNum].feature_set.feature[FEATURE_TEMPERATURE-FEATURE_MIN].target_value=value;
	break;
	/*   case FEATURE_WHITE_BALANCE+BU*4: // why oh why is there a *4? */
	/*     if (dc1394_set_white_balance(cameras[camNum].handle, cameras[camNum].node, value, cameras[camNum].feature_set.feature[FEATURE_WHITE_BALANCE-FEATURE_MIN].RV_value)!=DC1394_SUCCESS) */
	/*       printf("\nCould not set B/U white balance\n"); */
	/*     else { */
	/*       cameras[camNum].feature_set.feature[FEATURE_WHITE_BALANCE-FEATURE_MIN].BU_value=value; */
	/*       if (cameras[camNum].feature_set.feature[FEATURE_WHITE_BALANCE-FEATURE_MIN].absolute_capable!=0) { */
	/* 	GetAbsValue(FEATURE_WHITE_BALANCE); */
	/*       } */
	/*     } */
	/*     break; */
	/*   case FEATURE_WHITE_BALANCE+RV*4: // why oh why is there a *4? */
	/*     if (dc1394_set_white_balance(cameras[camNum].handle, cameras[camNum].node, cameras[camNum].feature_set.feature[FEATURE_WHITE_BALANCE-FEATURE_MIN].BU_value, value)!=DC1394_SUCCESS) */
	/*       printf("\nCould not set R/V white balance\n"); */
	/*     else { */
	/*       cameras[camNum].feature_set.feature[FEATURE_WHITE_BALANCE-FEATURE_MIN].RV_value=value; */
	/* /\*       if (cameras[camNum].feature_set.feature[FEATURE_WHITE_BALANCE-FEATURE_MIN].absolute_capable!=0) { *\/ */
	/* /\* 	GetAbsValue(FEATURE_WHITE_BALANCE); *\/ */
	/* /\*       } *\/ */
	/*     } */
	/*     break; */
    case FEATURE_WHITE_SHADING:
	fprintf(stderr,"Not yet implemented\n");
	break;
    
    default: // includes trigger_count
	if (dc1394_set_feature_value(cameras[camNum].handle, cameras[camNum].camera.node, feature, value)!=DC1394_SUCCESS)
	    printf("\nCould not set feature\n");
	else {
	    cameras[camNum].feature_set.feature[feature-FEATURE_MIN].value=value;
	    /*       if (feature!=FEATURE_TRIGGER) { */
	    /* 	if (cameras[camNum].feature_set.feature[feature-FEATURE_MIN].absolute_capable!=0) { */
	    /* 	  GetAbsValue((int)user_data); */
	    /* 	} */
	    /*       } */
	}
	/*      optical filter sometimes changes white balance (sony cameras) so we update the WB. */
	/*     if (feature==FEATURE_OPTICAL_FILTER) { */
	/*       UpdateRange(FEATURE_WHITE_BALANCE); */
	/*     } */
	break;
    }
    return 1;
}

int dc_auto_on_off_feature(camera_control *cameras, int camNum, int feature,int value)
{
    /*   if(cameras[camNum].feature_set.feature[feature-FEATURE_MIN].on_off_capable) */
    /*   { */
    /*     dc1394_feature_on_off(cameras[camNum].handle, cameras[camNum].camera.node, feature, true); */
    /*     cameras[camNum].feature_set.feature[feature-FEATURE_MIN].is_on=true; */
    /*   } */
    /*   else */
    /*   { */
    /*     printf("\nERROR this feature %d does not support on/off\n", feature); */
    /*     return -1; */
    /*   } */


    if(cameras[camNum].feature_set.feature[feature-FEATURE_MIN].auto_capable &&
       cameras[camNum].feature_set.feature[feature-FEATURE_MIN].manual_capable)
    {
	dc1394_auto_on_off(cameras[camNum].handle, cameras[camNum].camera.node,
			   cameras[camNum].feature_set.feature[feature-FEATURE_MIN].feature_id, value);
	if(value)
	    cameras[camNum].feature_set.feature[feature-FEATURE_MIN].auto_active=(dc1394bool_t)true;
	else 
	    cameras[camNum].feature_set.feature[feature-FEATURE_MIN].auto_active=(dc1394bool_t)false;

    }
    else
    {
	printf("\nERROR cam doesn't support manual/auto mode\n");
	return -1;
    }
  
    return 1;
}

int dc_on_off_feature(camera_control *cameras, int camNum, int feature, int value)
{
    if(cameras[camNum].feature_set.feature[feature-FEATURE_MIN].on_off_capable)
    {
	printf("\nFeature %d does not support on/off", feature);
	return -1;
    }

    if (dc1394_feature_on_off(cameras[camNum].handle, cameras[camNum].camera.node, feature, false)!=DC1394_SUCCESS)
    {
	printf("\nCould not set feature on/off");
	return -1;
    }
    else 
	cameras[camNum].feature_set.feature[feature-FEATURE_MIN].is_on= (dc1394bool_t)value;

    return 1;
}

int dc_set_features(camera_control *cameras, int camNum)
{
    int i=0;
    for(i=FEATURE_MIN;i<(FEATURE_MAX+1);i++)
    {
	if(cameras[camNum].feature_set.feature[i-FEATURE_MIN].available &&
	   cameras[camNum].feature_set.feature[i-FEATURE_MIN].auto_capable)
	    dc_auto_on_off_feature(cameras, camNum, i, true);
    }
    return 1;
}

